package com.magenta.maxoptra.gis;

/*
* Project: MaxOptRA v1.1
* User: Ivan Usalko
* Date: 20.01.2009 11:49:36
*
* Copyright (c) 1999-2009 Magenta Corporation Ltd. All Rights Reserved.
* Magenta Technology proprietary and confidential.
* Use is subject to license terms.
*/
public class GeoPrecision {

    //5 sign after zero (on 1 degree) ~ 1,2 m
    // how many digits must be in mantissa
    //public static final int COORDINATES_PRECISION = 4;
    public static final double SIGN_FACTOR_LAT = Math.pow(10.0, GisConstants.MAX_LATITUDE_ACCURACY);
    public static final double SIGN_FACTOR_LON = Math.pow(10.0, GisConstants.MAX_LONGITUDE_ACCURACY);

    public static double longitudeRound(double longitude) {
        return Math.round(longitude * SIGN_FACTOR_LON) / SIGN_FACTOR_LON;
    }
    public static double latitudeRound(double latitude) {
        return Math.round(latitude * SIGN_FACTOR_LAT) / SIGN_FACTOR_LAT;
    }

    public static double convertFromMinutesToDegree(double minutes) {
        return minutes / 60d;
    }

    public static double convertFromDegreeToMinutes(double degrees) {
        return degrees * 60d;
    }

    private static final double ONE_METER_IN_MILE = 0.00062137119;
    public static double convertFromMetersToMiles(double meters) {
        return meters * ONE_METER_IN_MILE;
    }

    public static long convertFromSecondsToMillis(int seconds) {
        return seconds * 1000L;
    }

    public static final long convertFromMinutesToMillis(double minutes) {
        return (long) (minutes * 60000L);
    }

    public static final long minToMillis(double minutes) {
        return (long) (minutes * 60000L);
    }

    private static double quad(double value) {
        return value * value;
    }
    /**
     * See trigonometry or http://en.wikipedia.org/wiki/Earth_radius.
     * @param latitude in degree (from -90 to +90).
     * @return meters in one degree of longitude.
     */
    //TODO ivictus: where calculate absolute error?
    private static double metersInOneDegree(double latitude) {
        //Radius at a given geodetic latitude:
        double aInKm = Geoid.EQUATORIAL_RADIUS_IN_METTERS / 1000.0;
        double bInKm = Geoid.POLAR_RADIUS_IN_METTERS / 1000.0;
        double latInRad = latitude * Math.PI / 180.0;
        double radiusInKm = Math.sqrt(
                (quad(quad(aInKm) * Math.cos(latInRad)) + quad(quad(bInKm) * Math.sin(latInRad))) /
                (quad(aInKm * Math.cos(latInRad)) + quad(bInKm * Math.sin(latInRad))));
        return ((2.0 * Math.PI * (radiusInKm * Math.cos(latInRad))) / 360.0) * 1000.0;
    }

    public static double convertFromMetersToLongitudeDeltaInDegree(double latitude, double meters) {
         return meters / metersInOneDegree(latitude);
    }

    public static double convertFromMetersToLatitudeDeltaInDegree(double meters) {
         return meters / metersInOneDegree(0);
    }

    public static class Geoid {
        public static double EQUATORIAL_RADIUS_IN_METTERS = 6378137.00;
        public static double POLAR_RADIUS_IN_METTERS = 6356752.30;
    }

    public static void main(String[] args) {
        System.out.println(String.format("LATITUDE : %f, METERS IN ONE DEGREE : %f", 0.0, metersInOneDegree(0.0)));
        System.out.println(String.format("LATITUDE : %f, METERS IN ONE DEGREE : %f", 90.0, metersInOneDegree(90.0)));
        System.out.println(String.format("LATITUDE : %f, METERS IN ONE DEGREE : %f", -90.0, metersInOneDegree(-90.0)));
        System.out.println(String.format("LATITUDE : %f, METERS IN ONE DEGREE : %f", 30.0, metersInOneDegree(30.0)));
        System.out.println(String.format("LATITUDE : %f, METERS IN ONE DEGREE : %f", -30.0, metersInOneDegree(-30.0)));
        System.out.println(String.format("LATITUDE : %f, METERS IN ONE DEGREE : %f", 45.0, metersInOneDegree(45.0)));
        System.out.println(String.format("LATITUDE : %f, METERS IN ONE DEGREE : %f", -45.0, metersInOneDegree(-45.0)));
        System.out.println(String.format("LATITUDE : %f, METERS IN ONE DEGREE : %f", 60.0, metersInOneDegree(60.0)));
        System.out.println(String.format("LATITUDE : %f, METERS IN ONE DEGREE : %f", -60.0, metersInOneDegree(-60.0)));
        System.out.println(String.format("LATITUDE : %f, METERS IN ONE DEGREE : %f", 50.0, metersInOneDegree(50.0)));
    }
}
